from format_check import *
from exts import BlogMongodb, all_logger
from datetime import datetime


class BlogModel:
    def __init__(
            self,
            title: str,
            author: str,
            content: str,
            category: str,
            tags: list,
            status: str = "draft",
            cover_image: str = None,
            slug: str = None,
            summary: str = None,
            allow_comments: bool = True,
            meta_description: str = None
    ):
        """初始化并进行字段验证"""
        try:
            # 核心元数据
            self.title = StringField(max_length=120, min_length=5, required=True).validate(title, "title")
            self.author = ReferenceField(reference_collection="users", required=True).validate(author, "author")
            self.slug = SlugField(required=True).validate(slug if slug else title.lower().replace(" ", "-"))

            # 内容相关
            self.content = TextField(min_length=200, required=True).validate(content, "content")
            self.summary = StringField(max_length=200).validate(summary if summary else content[:197] + "...")

            # 分类系统
            self.category = StringField(allowed_values=["技术", "生活", "公告", "资源"], required=True).validate(
                category, "category")
            self.tags = ListField(StringField(max_length=20), max_elements=8).validate(tags, "tags")

            # 状态控制
            self.status = StringField(allowed_values=["draft", "published", "archived"], required=True).validate(status,
                                                                                                                 "status")
            self.created_at = DateTimeField(auto_now=True).validate()
            self.updated_at = DateTimeField(auto_now=True).validate()

            # 互动数据
            self.views = IntegerField(min_value=0).validate(0)
            self.likes = ListField(ReferenceField(reference_collection="users")).validate([])
            self.comments = ListField(field_type=dict).validate([])  # 嵌套评论结构

            # SEO优化
            self.meta_description = StringField(max_length=160).validate(meta_description)
            self.cover_image = URLField().validate(cover_image)
            self.allow_comments = BooleanField().validate(allow_comments)

        except ValidationError as e:
            all_logger.error(f"博客验证失败: {str(e)}")
            raise BlogValidationError(f"字段验证错误: {str(e)}")
        except Exception as e:
            all_logger.error(f"未知错误: {type(e)} - {str(e)}")
            raise BlogCreationError("博客创建失败")

    def get_blog_info(self):
        """获取完整博客信息字典"""
        return {
            "title": self.title,
            "author": self.author,
            "slug": self.slug,
            "content": self.content,
            "category": self.category,
            "tags": self.tags,
            "status": self.status,
            "created_at": self.created_at,
            "updated_at": self.updated_at,
            "views": self.views,
            "likes": self.likes,
            "comments": self.comments,
            "meta_description": self.meta_description,
            "cover_image": self.cover_image,
            "allow_comments": self.allow_comments
        }

    def get_preview_info(self):
        """获取用于列表展示的简化信息"""
        return {
            "title": self.title,
            "author": self.author,
            "slug": self.slug,
            "summary": self.summary,
            "category": self.category,
            "tags": self.tags,
            "created_at": self.created_at,
            "views": self.views,
            "likes_count": len(self.likes),
            "comments_count": len(self.comments)
        }

    def save(self):
        """保存到数据库"""
        if BlogMongodb.find_one({"slug": self.slug}):
            raise DuplicateSlugError("该固定链接已被使用")
        if BlogMongodb.find_one({"title": self.title}):
            raise DuplicateTitleError("相同标题已存在")

        try:
            BlogMongodb.insert_one(self.get_blog_info())
            all_logger.info(f"博客已创建：{self.slug}")
        except Exception as e:
            all_logger.error(f"数据库保存失败：{str(e)}")
            raise DatabaseOperationError("博客保存失败")

    def update_blog(self, update_data: dict):
        """更新博客内容"""
        try:
            # 动态更新字段并重新验证
            for field, value in update_data.items():
                if hasattr(self, field):
                    # 特殊处理更新时间
                    if field == "content":
                        self.updated_at = datetime.now()
                    # 重新验证字段
                    validator = self._get_validator_for_field(field)
                    validated_value = validator.validate(value)
                    setattr(self, field, validated_value)

            BlogMongodb.update_one(
                {"slug": self.slug},
                {"$set": self.get_blog_info()}
            )
            all_logger.info(f"博客已更新：{self.slug}")
        except Exception  as e:
            raise BlogUpdateError(f"更新验证失败：{str(e)}")

    def add_comment(self, user: str, content: str):
        """添加评论"""
        if not self.allow_comments:
            raise CommentDisabledError("该博客已禁用评论")

        new_comment = {
            "user": ReferenceField(reference_collection="users").validate(user),
            "content": StringField(max_length=500, min_length=2).validate(content),
            "created_at": datetime.now(),
            "replies": []
        }

        self.comments.append(new_comment)
        BlogMongodb.update_one(
            {"slug": self.slug},
            {"$push": {"comments": new_comment}}
        )

    def increment_views(self):
        """增加浏览次数"""
        self.views += 1
        BlogMongodb.update_one(
            {"slug": self.slug},
            {"$inc": {"views": 1}}
        )

    @classmethod
    def get_by_slug(cls, slug: str):
        """通过slug获取博客实例"""
        blog_data = BlogMongodb.find_one({"slug": slug})
        if not blog_data:
            raise BlogNotFoundError("指定博客不存在")

        return cls(**cls._transform_mongo_data(blog_data))

    @staticmethod
    def _transform_mongo_data(data: dict) -> dict:
        """转换MongoDB数据格式"""
        return {
            "title": data["title"],
            "author": data["author"],
            "content": data["content"],
            "category": data["category"],
            "tags": data["tags"],
            "status": data["status"],
            "slug": data["slug"],
            "cover_image": data.get("cover_image"),
            "meta_description": data.get("meta_description")
        }


# 自定义异常类
class BlogValidationError(Exception): pass


class BlogCreationError(Exception): pass


class BlogUpdateError(Exception): pass


class DuplicateSlugError(Exception): pass


class DuplicateTitleError(Exception): pass


class CommentDisabledError(Exception): pass


class BlogNotFoundError(Exception): pass


class DatabaseOperationError(Exception): pass